﻿using Haidou.Wpf.UI.ViewModel;
using System;
using System.Security.Cryptography;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using WPoint = System.Windows.Point;
using WMouseEventArgs = System.Windows.Input.MouseEventArgs;

namespace Haidou.Wpf.UI.Windows.Composer
{
    /// <summary>
    /// FloatingBallWindows.xaml 的交互逻辑
    /// </summary>
    public partial class FloatingBallWindows : Window
    {
        private bool _dragging;
        private bool _movedDuringDrag;
        private WPoint _dragOffset;
        private double _normalSize = 100; // Core button size
        private bool _docked;
        private double _dockScale = 0.55; // scale when docked
        private Thickness _workAreaPadding = new(4);

        public FloatingBallWindows()
        {
            InitializeComponent();
            CoreBtn.PreviewMouseLeftButtonDown += CoreBtn_PreviewMouseLeftButtonDown;
            CoreBtn.PreviewMouseLeftButtonUp += CoreBtn_PreviewMouseLeftButtonUp;
            CoreBtn.PreviewMouseMove += CoreBtn_PreviewMouseMove;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            CoreBtn.Width = CoreBtn.Height = _normalSize;
            UpdateCenterTag();
            MouseEnter += (_, _) => ExpandFromDock();
            MouseLeave += async (_, _) => await MaybeShrinkAfterLeave();
        }

        // Window 背景区域双击仍然展开/收起
        private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton != MouseButton.Left) return;
            if (e.ClickCount == 2 && DataContext is FloatingHubViewModel vm)
            {
                vm.IsExpanded = !vm.IsExpanded;
            }
        }

        private void CoreBtn_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _dragging = true;
            _movedDuringDrag = false;
            _docked = false;
            _dragOffset = e.GetPosition(this);
            CoreBtn.CaptureMouse();
        }

        private void CoreBtn_PreviewMouseMove(object sender, WMouseEventArgs e)
        {
            if (!_dragging) return;
            var pos = e.GetPosition(this);
            var delta = pos - _dragOffset;
            if (!_movedDuringDrag && (Math.Abs(delta.X) > 2 || Math.Abs(delta.Y) > 2))
                _movedDuringDrag = true;

            // 使用当前屏幕坐标 + 偏移移动窗口
            var screenPos = PointToScreen(pos);
            Left = screenPos.X / DpiScaleX - _dragOffset.X;
            Top = screenPos.Y / DpiScaleY - _dragOffset.Y;
            UpdateCenterTag();
        }

        private void CoreBtn_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!_dragging) return;
            _dragging = false;
            CoreBtn.ReleaseMouseCapture();
            if (_movedDuringDrag)
            {
                SnapToEdge();
            }
            else
            {
                // 认为是点击
                if (DataContext is FloatingHubViewModel vm)
                    vm.IsExpanded = !vm.IsExpanded;
            }
        }

        private void UpdateCenterTag()
        {
            CoreBtn.Tag = new WPoint(CoreBtn.Width / 2, CoreBtn.Height / 2);
        }

        private double DpiScaleX => VisualTreeHelper.GetDpi(this).DpiScaleX;
        private double DpiScaleY => VisualTreeHelper.GetDpi(this).DpiScaleY;

        private void SnapToEdge()
        {
            var wa = SystemParameters.WorkArea; // 屏幕工作区
            double threshold = 40; // 进入贴边阈值
            double targetLeft = Left;
            double targetTop = Top;

            bool dockLeft = Left <= wa.Left + threshold;
            bool dockRight = (Left + Width) >= (wa.Right - threshold);
            bool dockTop = Top <= wa.Top + threshold;
            bool dockBottom = (Top + Height) >= (wa.Bottom - threshold);

            if (dockLeft) targetLeft = wa.Left + _workAreaPadding.Left;
            else if (dockRight) targetLeft = wa.Right - Width - _workAreaPadding.Right;

            if (dockTop) targetTop = wa.Top + _workAreaPadding.Top;
            else if (dockBottom) targetTop = wa.Bottom - Height - _workAreaPadding.Bottom;

            bool anyDock = dockLeft || dockRight || dockTop || dockBottom;
            AnimateWindowTo(targetLeft, targetTop);
            if (anyDock)
            {
                _docked = true;
                ShrinkToDock();
            }
            else
            {
                RestoreScale();
            }
        }

        private void AnimateWindowTo(double x, double y)
        {
            var easing = new QuadraticEase();
            BeginAnimation(Window.LeftProperty, new DoubleAnimation(x, TimeSpan.FromMilliseconds(180)) { EasingFunction = easing });
            BeginAnimation(Window.TopProperty, new DoubleAnimation(y, TimeSpan.FromMilliseconds(180)) { EasingFunction = easing });
        }

        private void ShrinkToDock()
        {
            if (FindName("CoreScale") is not ScaleTransform scale) return;
            var anim = new DoubleAnimation(_dockScale, TimeSpan.FromMilliseconds(180)) { EasingFunction = new QuadraticEase() };
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, anim);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, anim);
        }

        private void RestoreScale()
        {
            if (FindName("CoreScale") is not ScaleTransform scale) return;
            var anim = new DoubleAnimation(1, TimeSpan.FromMilliseconds(160)) { EasingFunction = new QuadraticEase() };
            scale.BeginAnimation(ScaleTransform.ScaleXProperty, anim);
            scale.BeginAnimation(ScaleTransform.ScaleYProperty, anim);
        }

        private void ExpandFromDock()
        {
            if (_docked) RestoreScale();
        }

        private async System.Threading.Tasks.Task MaybeShrinkAfterLeave()
        {
            if (!_docked) return;
            await System.Threading.Tasks.Task.Delay(800);
            if (!IsMouseOver && _docked) ShrinkToDock();
        }

        public static class VaultCrypto
        {
            public static (byte[] cipher, byte[] nonce, byte[] tag, byte[] salt) Encrypt(string plain, string password)
            {
                byte[] salt = RandomNumberGenerator.GetBytes(16);
                using var derive = new Rfc2898DeriveBytes(password, salt, 100_000, System.Security.Cryptography.HashAlgorithmName.SHA256);
                byte[] key = derive.GetBytes(32);
                byte[] nonce = RandomNumberGenerator.GetBytes(12);
                byte[] plainBytes = System.Text.Encoding.UTF8.GetBytes(plain);
                byte[] cipher = new byte[plainBytes.Length];
                byte[] tag = new byte[16];
                using var aes = new AesGcm(key);
                aes.Encrypt(nonce, plainBytes, cipher, tag);
                Array.Clear(key); // 安全
                return (cipher, nonce, tag, salt);
            }
        }
    }
}
